fix(tasks): stamp agent source server-side - #788
Conversation
lilyshen0722
left a comment
There was a problem hiding this comment.
Review — @sprint-review · head 406e599c · APPROVE
Mechanical note: this identity authored the PR, so GitHub rejects --approve; this is a review event carrying the verdict in text.
What it fixes, and why it matters beyond its size
Task.source was caller-supplied from the request body, defaulted to 'human', and is exposed as an agent-settable input on commonly_create_task. So a provenance-shaped field could be set to 'human' by an agent — or left unset and labelled human by default. Any future guard reading it (task.source === 'human') would have been satisfiable by the monitored party doing nothing.
This PR resolves it at the only correct layer:
const taskSource = req.agentUser?._id
? 'agent'
: source || (ghNumber ? 'github' : 'human');Server-side, derived from the authenticated caller, ignores the body claim for agent-authenticated creates, and leaves the human GitHub/import override untouched. req.agentUser is populated on both agent auth paths, so there is no branch where an agent slips through as human.
Correctly scoped: no speculative createdBy schema. That belongs in ADR-016's migration section, and shipping it here would have been an unratified schema decision riding a bugfix.
Verified by mutation
Replacing taskSource with the original body-honouring expression:
✕ stamps agent-authenticated creates as agent even when the body claims human
Expected: "agent" Received: "human"
✓ preserves the existing source override for human-authenticated imports
Tests: 1 failed, 1 passed
Exactly the adversarial assertion, no collateral — the human-path assertion stays green, confirming the fix is narrow rather than a blanket override. Baseline 2/2 under Node 22. All CI green.
NOT verified
- Node 26 cannot load this suite (
jsonwebtoken→buffer-equal-constant-time→SlowBuffer, removed in Node 26). I ran it under Node 22. Pre-existing and unrelated to this PR, confirmed on cleanmainearlier tonight — but it means this suite is invisible to anyone running the default toolchain locally, which is worth anengines/.nvmrcline inbackend/. - No live/staging request; everything is jest against
mongodb-memory-server. - I did not verify the repo-wide lint claim — @sprint-impl reported it red on pre-existing resolver failures and declined to claim green, which is the right call and I did not independently reproduce it.
- I did not check whether any other route accepts a caller-supplied provenance-shaped field with a favourable default. That sweep is worth doing; this fix addresses the one instance we found.
Closes #787.
What changed
source: "agent"server-side, ignoring a caller-supplied provenance claim.source: "human"with an agent token and verifies both the response and Mongo record remainagent.Verification
tasks.source-provenance+tasks.source-ref-idempotency).npm run tsc:checkpasses.Expected agent, Received human); restoring it returns 2/2 green.git diff --checkpasses.Not verified